using System;
using System.Collections;

namespace FunctionScope.Models
{
    /// <summary>
    /// Encapsulates a collection of TraceSampleModels. Fixed arrays are used for performance and cannot be resized once created.
    /// A circular buffer is used and a standard IEnumerable interface is provided. Lock SyncRoot when accessing to prevent race 
    /// conditions.
    /// </summary>
    /// <typeparam name="Type">The</typeparam>
    public class TraceModel<Type> : IEnumerable
    {

        public Object SyncRoot { get; } = new object();

        public TraceSampleModel<Type>[] Data { get; set; }
        public int Cursor { get; set; }
        public int Length { get; private set; }

        public Type MinX { get; set; }
        public Type MinY { get; set; }
        public Type MaxX { get; set; }
        public Type MaxY { get; set; }

        public TraceModel(int length)
        {
            ResetTraceSize(length);
        }

        /// <summary>
        /// Reset trace length to a given size. Clears all trace data
        /// </summary>
        /// <param name="length">The new trace size</param>
        public void ResetTraceSize(int length)
        {

            //Create a new array of the requested size
            Length = length;
            Data = new TraceSampleModel<Type>[Length];

            for (int i = 0; i < Length; i++)
                Data[i] = new TraceSampleModel<Type>();
        }

        /// <summary>
        /// Pushes sample data into the next slot in the buffer. Old data will be overwritten
        /// </summary>
        /// <param name="x">X value</param>
        /// <param name="y">Y value</param>
        /// <param name="t">T value</param>
        public void Push(Type x, Type y, Type t)
        {
            if (++Cursor >= Length)
            {
                Cursor = 0;
            }

            TraceSampleModel<Type> sample = Data[Cursor];
            sample.T = t;
            sample.Y = y;
            sample.X = x;

        }

        /// <summary>
        /// Returns the youngest sample in the collection
        /// </summary>
        public TraceSampleModel<Type> Head
        {
            get { return Data[Cursor]; }
        }

        /// <summary>
        /// Returns the oldest sample in the collection
        /// </summary>
        public TraceSampleModel<Type> Tail
        {
            get
            {
                int p = Cursor - 1;
                if (p < 0)
                    p = Length - 1;

                return Data[p];
            }
        }

        /// <summary>
        /// Enumerates the sample collection from oldest to the youngest
        /// </summary>
        /// <returns>Enumerations of TraceModel<Type></returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            int s = Cursor + 1; //Move to tail
            int c = 0;

            while (c++ < Length)
            {
                yield return Data[s >= Length ? s = 0 : s++];
            }

        }
    }
}